/**
 * 一个函数return另外一个函数 这个函数叫做高阶函数
 * 抽象叫once的过程
 * 参数是一个函数，把里面的任何一个函数变成只能调用一次的函数
 * @param {*} fn
 * @returns
 */
function once(fn) {
  // outer scope  closure...
  return function (...args) {
    // inner scope
    if (fn) {
      const ret = fn.apply(this, args);
      fn = null;
      return ret;
    }
  };
}

const list = document.querySelector('ul');
const buttons = list.querySelectorAll('button');
buttons.forEach((button) => {
  button.addEventListener(
    'click',
    once((evt) => {
      const target = evt.target;
      target.parentNode.className = 'completed';
      setTimeout(() => {
        list.removeChild(target.parentNode);
      }, 2000);
    })
  );
});

const foo1 = () => {
  console.log('foo1');
};

foo1();
foo1();
foo1();

const foo2 = once(() => {
  console.log('foo2');
});

foo2();
foo2();
foo2();

/**
 * 等价高阶函数
 * @param {} fn
 * @returns
 */
function HOF0(fn) {
  return function (...args) {
    return fn.apply(this, args);
  };
}

/**
 * 常用高阶函数
 * Once
 * Throttle
 * Debounce
 * Consumer/2
 * Iterative
 */

/**
 * 节流
 * @param {*} fn
 * @param {*} time
 * @returns
 */
function throttle(fn, time = 500) {
  let timer;
  return function (...args) {
    if (!timer) {
      fn.apply(this, args);
      timer = setTimeout(() => {
        timer = null;
      }, time);
    }
  };
}

/**
 * 防抖
 * @param {*} fn
 * @param {*} time
 * @returns
 */
function debounce(fn, time = 500) {
  let timer;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, time);
  };
}
